/*
 * Listener.java
 */

package org.sunspotworld.demo;

import com.sun.spot.io.j2me.radiogram.*;
import com.sun.spot.peripheral.NoAckException;
import com.sun.spot.peripheral.TimeoutException;
import com.sun.spot.util.IEEEAddress;

import java.io.*;
import javax.microedition.io.*;
import java.sql.*;
import java.util.Vector;

/**
 * @author krish
 */
public class Listener extends Thread implements PacketTypes,SensorTypes{

    private boolean baseStationPresent = false;
    private RadiogramConnection conn = null;
    private Radiogram xdg = null;
    private boolean running = true;
    private boolean connected = false;
    private long spotAddress = 0;
    private long timeStampOffset = -1;
    private int index = 0;
    private int scaleInUse = 2;
    //
    private String connected_port;
    //
    private Vector mySPOTLIST;  // Vector itself is synchronized
    // Shared Variable. Need synchronization
    private BitMap PORTBitMap;
    private Vector sensorFormat = null;

    //TODO: check if the database operations are thread safe
    public MainFrame myGUI;
    
    /**Constructor
     *
     * @param port
     */
//    public Listener (String port) {
//        connected_port = port;
//        sensorFormat = new Vector();
//        init();
//    }

    /**Overloaded Constructor
     *
     * @param port
     * @param SPOTLIST
     * @param PORTBitMap 
     * @param GUI
     */
    //TODO- Dont need whole GUI, try to get the array of panels
    public Listener (String port, Vector SPOTLIST, BitMap PORTBitMap, MainFrame GUI) {
        connected_port = port;
        this.PORTBitMap = PORTBitMap;
        //synchronized(SPOTLIST){
        this.mySPOTLIST = SPOTLIST;
        //}
        this.myGUI = GUI;
        init();
    }
    
    /**
     * Connect to base station & other initialization.
     */
    private void init () {
        RadiogramConnection rcvConn = null;
        try {
            rcvConn = (RadiogramConnection)Connector.open("radiogram://:" + connected_port);
            baseStationPresent = true;
        } catch (Exception ex) {
            baseStationPresent = false;
            System.out.println("Problem connecting to base station: " + ex);
        } finally {
            try {
                if (rcvConn != null) {
                    rcvConn.close();
                }
            } catch (IOException ex) { 
                //ignore
            }
        }
    }
    
     private void sendCmd (byte sensor, byte cmd){
        if (conn != null) {
            try {
                xdg.reset();
                xdg.writeByte(sensor);
                xdg.writeByte(cmd);
                conn.send(xdg);
            } catch (NoAckException nex) {
                connected = false;
               // updateConnectionStatus(connected);
            } catch (IOException ex) {
                //ignore any other problems
            }
        }
    }

    public void addSensor(byte sensorType){
        //TODO to add support sensorType+packetType
        sendCmd(sensorType,ADD_SENSOR);
    }

    public void finishConfig(){
        //TODO
        sendCmd(GENERIC,FINISH_CONFIG_REQ);

    }

    /** wait for spot is used in the thread.
     */
    private void waitForSpot () {
       RadiogramConnection rcvConn = null;
       DatagramConnection txConn = null;
       spotAddress = 0;
       try {
            rcvConn = (RadiogramConnection)Connector.open("radiogram://:" + connected_port);
            rcvConn.setTimeout(10000);             // timeout in 10 seconds
            Datagram dg = rcvConn.newDatagram(rcvConn.getMaximumLength());
            while (true) {
                try {
                    dg.reset();
                    rcvConn.receive(dg); // wait until we receive a request
                    if (dg.readByte() == LOCATE_DISPLAY_SERVER_REQ) {
                        // type of packet
                        String addr = dg.getAddress();
                        IEEEAddress ieeeAddr = new IEEEAddress(addr);
                        long macAddress = ieeeAddr.asLong();
                        System.out.println("Received request from: " + ieeeAddr.asDottedHex());

                        Datagram rdg = rcvConn.newDatagram(10);
                        rdg.reset();
                        rdg.setAddress(dg);
                        rdg.writeByte(DISPLAY_SERVER_AVAIL_REPLY);  // packet type
                        rdg.writeLong(macAddress); // requestor's ID
                        rcvConn.send(rdg); // broadcast it
                        spotAddress = macAddress;
                        break;
                    }
                } catch (TimeoutException ex){
                    announceStarting();
                }
            }
        } catch (Exception ex) {
            System.out.println("Error waiting for remote Spot: " + ex.toString());
            ex.printStackTrace();
        } finally {
            try {
                if (rcvConn != null) {
                    rcvConn.close();
                }
                if (txConn != null) {
                    txConn.close();
                }
            } catch (IOException ex) { 
                // ignore
            }
        }
    }

     /**
     * Broadcast that the host display server is (re)starting.
     */
    private void announceStarting () {
        DatagramConnection txConn = null;
        try {

            txConn = (DatagramConnection)Connector.open("radiogram://broadcast:" + connected_port);
            Datagram dg = txConn.newDatagram(txConn.getMaximumLength());
            //send an update to the

            dg.writeByte(DISPLAY_SERVER_RESTART);        // packet type
            txConn.send(dg);                             // broadcast it
        } catch (Exception ex) {
            System.out.println("Error sending display server startup message: " + ex.toString());
            //ex.printStackTrace();
        } finally {
            try {
                if (txConn != null) {
                    txConn.close();
                }
            } catch (IOException ex) { 
                /* ignore */
            }
        }
    }

    @Override
    public void run () {
        if (baseStationPresent) {
            System.out.println("Listener Thread Started ...");
            hostLoop();
        }
    }

    /**
     * Main receive loop. Receive a packet sent by remote SPOT and handle it.
     */
    private void hostLoop() {
        running = true;
        announceStarting();  // announce we are starting up - in case a Spot thinks it's connected to us
        while (running) {
            //con = ClassDB.openConnection();     // Open Connection to Database
            waitForSpot();   // connect to a Spot with accelerometer telemetry to display

            if (spotAddress != 0) {
                try {
                    conn = (RadiogramConnection)Connector.open("radiogram://" + spotAddress + ":" + connected_port);
                    conn.setTimeout(1000);             // timeout every second
                    Radiogram rdg = (Radiogram)conn.newDatagram(conn.getMaximumLength());
                    xdg = (Radiogram)conn.newDatagram(10); // we never send more than 1 or 2 bytes
                    connected = true;
                    //updateConnectionStatus(connected);
                    index = 0;
                    timeStampOffset = -1;
                    while (connected) {
                        //loop to parse the recieved data
                        Byte sensortype = xdg.readByte();
                        Byte commandtype = xdg.readByte();
                        switch(sensortype){
                            //need to handle data once its recieved.
                            case GENERIC:{
                                //get the

                                break;
                            }
                            
                            /*case ACCELEROMETER_SENSOR_X:{

                                break;
                            }
                            case ACCELEROMETER_SENSOR_Y:{

                                break;
                            }
                            case ACCELEROMETER_SENSOR_Z:{

                                break;
                            }
                            case ACCELEROMETER_SENSOR_TILT_X:{

                                break;
                            }
                            case ACCELEROMETER_SENSOR_TILT_Y:{

                                break;
                            }
                            case ACCELEROMETER_SENSOR_TILT_Z:{

                                break;
                            }
                            case TEMP_SENSOR:{

                                break;
                            }
                            case LIGHT_SENSOR:{

                                break;
                            }
                            case A0:{

                                break;
                            }
                            case A1:{

                                break;
                            }
                            case A2:{

                                break;
                            }
                            case A3:{

                                break;
                            }*/

                        }
                    }
                } catch (Exception ex) {
                    System.out.println("Error communicating with remote Spot: " + ex.toString());
                } finally {
                    try {
                        //ClassDB.closeConnection(con);
                        connected = false;
                       // updateConnectionStatus(connected);
                        if (conn != null) {
                            xdg.reset();
                            xdg.writeByte(DISPLAY_SERVER_STOP);        // packet type
                            conn.send(xdg);                                // broadcast it
                            conn.close();
                            conn = null;
                        }
                    } catch (IOException ex) { /* ignore */ }
                }
            }
        }
        //running is false..
    }


    /**
     * Send a request to the remote SPOT to report on radio signal strength.
     */
    //public void doPing() {
      //  sendCmd(PING_REQ);
    //}

    /**
     * Send a request to the remote SPOT to blink its LEDs.
     */
    //public void doBlink() {
      //  sendCmd(BLINK_LEDS_REQ);
    //}

    /**
     * Pause running. Also notify the remote SPOT that we are no longer listening to it.
     */
    public void doPause () {
        sendCmd(GENERIC,DISPLAY_SERVER_PAUSE);
       // running = false;
    }

    /** Stop the thread and send command to the spot that the server is exiting
     *
     */
     public void doStop(){
        sendCmd(GENERIC,DISPLAY_SERVER_STOP);
        running = false;
        synchronized(mySPOTLIST){
               mySPOTLIST.remove(this);
        }
     }


}
